import { Injectable, Logger } from '@nestjs/common';
import { parse } from './utils';
import { Cron, CronExpression } from '@nestjs/schedule';
import * as dayjs from 'dayjs';
import { request } from './request_thread';

@Injectable()
export class AppService {
  private logger = new Logger('AppService');

  getHello(): string {
    return 'Hello World!';
  }

  public messages = new Map<
    string,
    {
      msgid: string;
      date: number;
      message: string;
      closed: boolean;
    }
  >();

  public cids = new Map<string, string>();

  /**
   * 5分钟检测一次
   * @private
   */
  @Cron(CronExpression.EVERY_5_MINUTES)
  private task() {
    this.logger.log('@Cron [task]');
    const values = this.messages.values();
    for (const fromElement of Array.from(values)) {
      if (dayjs().isAfter(dayjs(fromElement.date).add(5, 'minutes'))) {
        fromElement.closed = true;
        this.messages.delete(fromElement.msgid);
      }
    }
  }

  public request(user: string, msgid: string, body: Buffer, dtk: string) {
    const data = {
      msgid,
      date: Date.now(),
      message: '',
      closed: false,
    };

    this.messages.set(msgid, data);

    request(
      {
        port: 443,
        host: 'llm.mingqi-tech.cn',
        path: '/v1/chat-messages',
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Content-Length': body.length,
          Authorization: `Bearer ${dtk}`,
        },
        timeout: 120000,
      },
      body,
      (res) => {
        let message = '';
        res.on('data', (e: string) => {
          if (e) {
            message += e;
            const regexp = /\n\n/g;
            let exec: RegExpExecArray | null = null;
            let start = 0;
            while ((exec = regexp.exec(message))) {
              try {
                const str = exec.input
                  .slice(start, exec.index)
                  .trimStart()
                  .trimEnd()
                  .trim();

                if (/^data:\s/.test(str)) {
                  const { event, answer, conversation_id } = JSON.parse(
                    str.replace(/^data:\s/, ''),
                  ) as DifyMessage;

                  switch (event) {
                    case 'message':
                      data.message += answer ?? '';
                      break;
                    case 'message_end':
                      {
                        data.message += answer ?? '';
                        data.closed = true;
                      }
                      break;

                    case 'message_replace':
                      {
                        data.message = answer;
                      }
                      break;
                    case 'workflow_started': {
                      data.closed = false;
                      data.message = '';
                      this.cids.set(user, conversation_id);
                    }
                  }
                }
                start = exec.index;
              } catch (e) {
                data.closed = true;
                this.logger.error(e);
              }
            }
            message = message.slice(start);
          }
        });
        res.on('error', () => {
          data.closed = true;
        });
        res.on('end', () => {
          data.closed = true;
        });
      },
    );

    // return new Promise((resolve, reject) => {
    //   const clientRequest: ClientRequest = https.request(
    //     {
    //       port: 443,
    //       host: 'llm.mingqi-tech.cn',
    //       path: '/v1/chat-messages',
    //       method: 'POST',
    //       headers: {
    //         'Content-Type': 'application/json',
    //         'Content-Length': body.length,
    //         Authorization: `Bearer app-g9hJ68z6gh4eQFfxSxSfxVPZ`,
    //       },
    //       timeout: 120000,
    //     },
    //     (res) => {
    //       let message = '';
    //       res.on('data', (e: Buffer) => {
    //         if (e) {
    //           message += e.toString();
    //           const regexp = /\n\n/g;
    //           let exec: RegExpExecArray | null = null;
    //           let start = 0;
    //           while ((exec = regexp.exec(message))) {
    //             try {
    //               const str = exec.input
    //                 .slice(start, exec.index)
    //                 .trimStart()
    //                 .trimEnd()
    //                 .trim();
    //
    //               if (/^data:\s/.test(str)) {
    //                 const { event, answer, task_id } = JSON.parse(
    //                   str.replace(/^data:\s/, ''),
    //                 ) as DifyMessage;
    //
    //                 switch (event) {
    //                   case 'message':
    //                     data.message += answer ?? '';
    //                     break;
    //                   case 'message_end':
    //                     {
    //                       data.message += answer ?? '';
    //                       data.closed = true;
    //                     }
    //                     break;
    //
    //                   case 'message_replace':
    //                     {
    //                       data.message = answer;
    //                     }
    //                     break;
    //                   case 'workflow_started': {
    //                     data.closed = false;
    //                     data.message = '';
    //                     this.logger.log('[workflow_started] ' + task_id);
    //                   }
    //                 }
    //               }
    //               start = exec.index;
    //             } catch (e) {
    //               data.closed = true;
    //               this.logger.error(e);
    //               reject(e as Error);
    //             }
    //           }
    //           message = message.slice(start);
    //         }
    //       });
    //     },
    //   );
    //   clientRequest.on('error', (err) => {
    //     reject(err);
    //   });
    //   clientRequest.write(body);
    //   clientRequest.end();
    //   resolve(true);
    // });
  }

  public chatMessage(
    message: string,
    dtk: string = 'app-g9hJ68z6gh4eQFfxSxSfxVPZ',
  ) {
    const { parsed, body } = parse(message);
    this.logger.log(`[parsed] ` + JSON.stringify(parsed));
    this.logger.log(`[messages] ` + this.messages.size);

    if (parsed.stream?.id) {
      if (!this.messages.has(parsed.stream.id)) {
        return {
          msgtype: 'stream',
          stream: {
            id: parsed.msgid,
            finish: true,
            content: '消息已超时',
          },
        };
      }

      const data = this.messages.get(parsed.stream?.id ?? parsed.msgid);
      if (data) {
        const res = {
          msgtype: 'stream',
          stream: {
            id: data.msgid,
            finish: data.closed,
            content: data.message ?? '<think></think>',
          },
        };
        this.logger.log(`[chat] ` + JSON.stringify(res));
        if (data.closed) {
          this.messages.delete(parsed.stream?.id);
        }
        return res;
      }
    }

    try {
      const conversation_id = this.cids.get(body.user);
      if (conversation_id) {
        (body as any).conversation_id = conversation_id;
      }
      const postData = JSON.stringify(body);
      const bufferBuffer = Buffer.from(postData, 'utf-8');
      void this.request(parsed.from.userid, parsed.msgid, bufferBuffer, dtk);
    } catch {
      this.messages.delete(parsed.msgid);
    }

    return {
      msgtype: 'stream',
      stream: {
        id: parsed.msgid,
        finish: false,
        content: '',
      },
    };
  }
}
